package org.gdstash.db;

import org.gdstash.file.ARCDecompress;
import org.gdstash.file.ARZRecord;
import org.gdstash.ui.GDStashFrame;
import org.gdstash.util.GDConstants;
import org.gdstash.util.GDMsgFormatter;
import org.gdstash.util.GDMsgLogger;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.LinkedList;
import java.util.List;

public class DBFaction {
    private static final String TABLE_NAME = "GDC_FACTION";
    private static final int ROW_FACTION_ID = 1;
    private static final int ROW_BOUNTY_ENABLED = 2;
    private static final int ROW_QUEST_ENABLED = 3;
    private static final int ROW_FACTION_TAG = 4;
    private static final int ROW_FACTION_TEXT = 5;
    private String factionID;
    private boolean bountyEnabled;
    private boolean questEnabled;
    private String factionTag;
    private String factionText;

    public DBFaction() {
    }

    private DBFaction(final ARZRecord record) {
        this.factionID = record.getFileName();
        this.bountyEnabled = record.getFactionBountyEnabled();
        this.questEnabled = record.getFactionQuestEnabled();
        this.setFactionTag(record.getFactionTag());
    }

    private static List<DBFaction> wrap(final ResultSet rs) throws SQLException {
        final List<DBFaction> list = new LinkedList<DBFaction>();
        while (rs.next()) {
            final DBFaction faction = new DBFaction();
            faction.factionID = rs.getString(1);
            faction.bountyEnabled = rs.getBoolean(2);
            faction.questEnabled = rs.getBoolean(3);
            faction.factionTag = rs.getString(4);
            faction.factionText = rs.getString(5);
            if (faction.factionText != null) {
                final ByteBuffer buffer = StandardCharsets.UTF_8.encode(faction.factionText);
                final String utf8 = StandardCharsets.UTF_8.decode(buffer).toString();
                faction.factionText = utf8;
            }
            list.add(faction);
        }
        return list;
    }

    public String getFactionID() {
        return this.factionID;
    }

    public boolean isBountyEnabled() {
        return this.bountyEnabled;
    }

    public boolean isQuestEnabled() {
        return this.questEnabled;
    }

    public String getFactionTag() {
        return this.factionTag;
    }

    public static String getFactionTextByItemID(final String itemID) {
        String tableID = DBMerchantTableAlloc.getTableIDByItemID(itemID);
        if (tableID == null) {
            String s = null;
            int pos = itemID.indexOf("b_");
            if (pos == -1) {
                pos = itemID.indexOf("c_");
            }
            if (pos == -1) {
                pos = itemID.indexOf("d_");
            }
            if (pos != -1) {
                final String s2 = itemID.substring(0, pos);
                final String s3 = itemID.substring(pos + 2);
                s = s2 + "a_" + s3;
            }
            if (s != null) {
                tableID = DBMerchantTableAlloc.getTableIDByItemID(s);
            }
        }
        if (tableID == null) {
            final DBItemCraft craft = DBItemCraft.getByCraftID(itemID);
            if (craft != null) {
                tableID = DBMerchantTableAlloc.getTableIDByItemID(craft.getItemID());
            }
        }
        if (tableID == null) {
            return null;
        }
        final String tableSetID = DBMerchantTableSetAlloc.getTableSetIDByTableID(tableID);
        if (tableSetID == null) {
            return null;
        }
        final DBMerchant dbMerchant = DBMerchant.getByTableSetID(tableSetID);
        if (dbMerchant == null) {
            return null;
        }
        if (dbMerchant.getFactionID() == null) {
            return null;
        }
        final DBFaction dbFaction = get(dbMerchant.getFactionID());
        if (dbFaction == null) {
            return null;
        }
        return dbFaction.getFactionText();
    }

    private void setFactionTag(final String factionTag) {
        this.factionTag = factionTag;
        if (factionTag == null) {
            this.factionText = null;
        } else {
            final String tag = "tagFaction" + factionTag;
            this.factionText = GDStashFrame.arcList.getTag(ARCDecompress.FileModule.All, GDConstants.TAG_TEXT_UI, tag, false);
        }
    }

    public static void createTable() throws SQLException {
        final String dropTable = "DROP TABLE GDC_FACTION";
        final String createTable = "CREATE TABLE GDC_FACTION (FACTION_ID     VARCHAR(256) NOT NULL, BOUNTY_ENABLED BOOLEAN, QUEST_ENABLED  BOOLEAN, FACTION_TAG    VARCHAR(64), FACTION_TEXT   VARCHAR(256), PRIMARY KEY (FACTION_ID))";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final Statement st = conn.createStatement()) {
                if (GDDBUtil.tableExists(conn, "GDC_FACTION")) {
                    st.execute(dropTable);
                }
                st.execute(createTable);
                st.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                final Object[] args = {"GDC_FACTION"};
                final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_CREATE_TABLE", args);
                GDMsgLogger.addError(msg);
                throw ex;
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static void delete(final String factionID) throws SQLException {
        final String deleteEntry = "DELETE FROM GDC_FACTION WHERE FACTION_ID = ?";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(deleteEntry)) {
                ps.setString(1, factionID);
                ps.executeUpdate();
                ps.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
            } finally {
                conn.setAutoCommit(auto);
            }
        } catch (SQLException ex2) {
        }
    }

    public static void insert(final ARZRecord record) throws SQLException {
        final DBFaction entry = get(record.getFileName());
        if (entry != null) {
            return;
        }
        final DBFaction faction = new DBFaction(record);
        final String insert = "INSERT INTO GDC_FACTION VALUES (?,?,?,?,?)";
        try (final Connection conn = GDDBData.getConnection()) {
            final boolean auto = conn.getAutoCommit();
            conn.setAutoCommit(false);
            try (final PreparedStatement ps = conn.prepareStatement(insert)) {
                ps.setString(1, faction.factionID);
                ps.setBoolean(2, faction.bountyEnabled);
                ps.setBoolean(3, faction.questEnabled);
                ps.setString(4, faction.factionTag);
                ps.setString(5, faction.factionText);
                ps.executeUpdate();
                ps.clearParameters();
                ps.close();
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
                GDMsgLogger.addError(GDMsgFormatter.getString(GDMsgFormatter.rbMsg, "ERR_IN_GAME_CONFIG"));
                GDMsgLogger.addError(ex);
            } finally {
                conn.setAutoCommit(auto);
            }
        }
    }

    public static DBFaction get(final String factionID) {
        DBFaction faction = null;
        final String command = "SELECT * FROM GDC_FACTION WHERE FACTION_ID = ?";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            ps.setString(1, factionID);
            try (final ResultSet rs = ps.executeQuery()) {
                final List<DBFaction> list = wrap(rs);
                if (list.isEmpty()) {
                    faction = null;
                } else {
                    faction = list.get(0);
                }
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {factionID, "GDC_FACTION"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return faction;
    }

    public static List<DBFaction> getAll() {
        List<DBFaction> list = null;
        final String command = "SELECT * FROM GDC_FACTION";
        try (final Connection conn = GDDBData.getConnection();
             final PreparedStatement ps = conn.prepareStatement(command)) {
            try (final ResultSet rs = ps.executeQuery()) {
                list = wrap(rs);
                conn.commit();
            } catch (SQLException ex) {
                throw ex;
            }
        } catch (SQLException ex2) {
            final Object[] args = {"-", "GDC_FACTION"};
            final String msg = GDMsgFormatter.format(GDMsgFormatter.rbMsg, "ERR_READ_TABLE_BY_ID", args);
            GDMsgLogger.addError(msg);
            GDMsgLogger.addError(ex2);
        }
        return list;
    }

    public String getFactionText() {
        return this.factionText;
    }
}
